home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2003 August / MW 8 2003 CD1.iso / Inside Macworld / Product News / gimp-1.2.4.sit / gimp-1.2.4 / plug-ins / common / randomize.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-08-22  |  20.6 KB  |  783 lines

  1. /****************************************************************************
  2.  * This is a plugin for the GIMP v 1.0 or later.  Documentation is
  3.  * available at http://www.rru.com/~meo/gimp/ .
  4.  *
  5.  * Copyright (C) 1997-8 Miles O'Neal  <meo@rru.com>  http://www.rru.com/~meo/
  6.  * GUI based on GTK code from:
  7.  *    alienmap (Copyright (C) 1996, 1997 Daniel Cotting)
  8.  *    plasma   (Copyright (C) 1996 Stephen Norris),
  9.  *    oilify   (Copyright (C) 1996 Torsten Martinsen),
  10.  *    ripple   (Copyright (C) 1997 Brian Degenhardt) and
  11.  *    whirl    (Copyright (C) 1997 Federico Mena Quintero).
  12.  *
  13.  * This program is free software; you can redistribute it and/or modify
  14.  * it under the terms of the GNU General Public License as published by
  15.  * the Free Software Foundation; either version 2 of the License, or
  16.  * (at your option) any later version.
  17.  *
  18.  * This program is distributed in the hope that it will be useful,
  19.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21.  * GNU General Public License for more details.
  22.  *
  23.  * You should have received a copy of the GNU General Public License
  24.  * along with this program; if not, write to the Free Software
  25.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  26.  *
  27.  ****************************************************************************/
  28.  
  29. /****************************************************************************
  30.  * Randomize:
  31.  *
  32.  * randomize version 1.7 (1 May 1998, MEO)
  33.  *
  34.  * Please send any patches or suggestions to the author: meo@rru.com .
  35.  * 
  36.  * This plug-in adds a user-defined amount of randomization to an
  37.  * image.  Variations include:
  38.  * 
  39.  *  - hurling (spewing random colors)
  40.  *  - picking a nearby pixel at random
  41.  *  - slurring (a crude form of melting)
  42.  * 
  43.  * In any case, for each pixel in the selection or image,
  44.  * whether to change the pixel is decided by picking a
  45.  * random number, weighted by the user's "randomization" percentage.
  46.  * If the random number is in range, the pixel is modified.  Picking
  47.  * one selects the new pixel value at random from the current and
  48.  * adjacent pixels.  Hurling assigns a random value to the pixel.
  49.  * Slurring sort of melts downwards; if a pixel is to be slurred,
  50.  * there is an 80% chance the pixel above be used; otherwise, one
  51.  * of the pixels adjacent to the one above is used (even odds as
  52.  * to which it will be).
  53.  * 
  54.  * Picking, hurling and slurring work with any image type.
  55.  * 
  56.  * This plug-in's effectiveness varies a lot with the type
  57.  * and clarity of the image being "randomized".
  58.  * 
  59.  * Hurling more than 75% or so onto an existing image will
  60.  * make the image nearly unrecognizable.  By 90% hurl, most
  61.  * images are indistinguishable from random noise.
  62.  * 
  63.  * The repeat count is especially useful with slurring.
  64.  * 
  65.  * TODO List
  66.  * 
  67.  *  - add a real melt function
  68.  ****************************************************************************/
  69.  
  70. #ifdef HAVE_CONFIG_H
  71. #include "config.h"
  72. #endif
  73.  
  74. #include <stdio.h>
  75. #include <stdlib.h>
  76. #include <string.h>
  77. #include <time.h>
  78.  
  79. #include <gtk/gtk.h>
  80.  
  81. #include <libgimp/gimp.h>
  82. #include <libgimp/gimpui.h>
  83.  
  84. #include "libgimp/stdplugins-intl.h"
  85.  
  86.  
  87. /*********************************
  88.  *
  89.  *  PLUGIN-SPECIFIC CONSTANTS
  90.  *
  91.  ********************************/
  92.  
  93. /*
  94.  *  progress meter update frequency
  95.  */
  96. #define PROG_UPDATE_TIME ((row % 10) == 0)
  97.  
  98. gchar *PLUG_IN_NAME[] =
  99. {
  100.   "plug_in_randomize_hurl",
  101.   "plug_in_randomize_pick",
  102.   "plug_in_randomize_slur",
  103. };
  104.  
  105. gchar *RNDM_VERSION[] =
  106. {
  107.   N_("Random Hurl 1.7"),
  108.   N_("Random Pick 1.7"),
  109.   N_("Random Slur 1.7"),
  110. };
  111.  
  112. #define RNDM_HURL 1
  113. #define RNDM_PICK 2
  114. #define RNDM_SLUR 3
  115.  
  116. #define SEED_TIME 10
  117. #define SEED_USER 11
  118.  
  119. #define SCALE_WIDTH 100
  120.  
  121. gint rndm_type = RNDM_HURL;  /* hurl, pick, etc. */
  122.  
  123. /*********************************
  124.  *
  125.  *  PLUGIN-SPECIFIC STRUCTURES AND DATA
  126.  *
  127.  ********************************/
  128.  
  129. typedef struct
  130. {
  131.   gdouble rndm_pct;     /* likelihood of randomization (as %age) */
  132.   gdouble rndm_rcount;  /* repeat count */
  133.   gint    seed_type;    /* seed init. type - current time or user value */
  134.   gint    rndm_seed;    /* seed value for rand() function */
  135. } RandomizeVals;
  136.  
  137. static RandomizeVals pivals =
  138. {
  139.   50.0,
  140.   1.0,
  141.   SEED_TIME,
  142.   0,
  143. };
  144.  
  145. typedef struct
  146. {
  147.   gint run;
  148. } RandomizeInterface;
  149.  
  150. static RandomizeInterface rndm_int =
  151. {
  152.   FALSE     /*  have we run? */
  153. };
  154.  
  155.  
  156. /*********************************
  157.  *
  158.  *  LOCAL FUNCTIONS
  159.  *
  160.  ********************************/
  161.  
  162. static void query (void);
  163. static void run   (gchar   *name,
  164.            gint     nparams,
  165.            GimpParam  *param,
  166.            gint    *nreturn_vals,
  167.            GimpParam **return_vals);
  168.  
  169. static void randomize                    (GimpDrawable *drawable);
  170.  
  171. static inline void randomize_prepare_row (GimpPixelRgn *pixel_rgn,
  172.                       guchar    *data,
  173.                       gint       x,
  174.                       gint       y,
  175.                       gint       w);
  176.  
  177. static gint randomize_dialog             (void);
  178. static void randomize_ok_callback        (GtkWidget *widget,
  179.                       gpointer   data);
  180.  
  181. /************************************ Guts ***********************************/
  182.  
  183. GimpPlugInInfo PLUG_IN_INFO =
  184. {
  185.   NULL,  /* init_proc  */
  186.   NULL,  /* quit_proc  */
  187.   query, /* query_proc */
  188.   run,   /* run_proc   */
  189. };
  190.  
  191. MAIN ()
  192.  
  193. /*********************************
  194.  *
  195.  *  query() - query_proc
  196.  *
  197.  *      called by the GIMP to learn about this plug-in
  198.  *
  199.  ********************************/
  200.  
  201. static void
  202. query (void)
  203. {
  204.   static GimpParamDef args[] =
  205.   {
  206.     { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
  207.     { GIMP_PDB_IMAGE, "image", "Input image (unused)" },
  208.     { GIMP_PDB_DRAWABLE, "drawable", "Input drawable" },
  209.     { GIMP_PDB_FLOAT, "rndm_pct", "Randomization percentage (1.0 - 100.0)" },
  210.     { GIMP_PDB_FLOAT, "rndm_rcount", "Repeat count (1.0 - 100.0)" },
  211.     { GIMP_PDB_INT32, "seed_type", "Seed type (10 = current time, 11 = seed value)" },
  212.     { GIMP_PDB_INT32, "rndm_seed", "Seed value (used only if seed type is 11)" }
  213.   };
  214.   static gint nargs = sizeof(args) / sizeof (args[0]);
  215.  
  216.   const gchar *hurl_blurb =
  217.     "Add a random factor to the image by hurling random data at it.";
  218.   const gchar *pick_blurb =
  219.     "Add a random factor to the image by picking a random adjacent pixel.";
  220.   const gchar *slur_blurb =
  221.     "Add a random factor to the image by slurring (similar to melting).";
  222.  
  223.   const gchar *hurl_help =
  224.     "This plug-in ``hurls'' randomly-valued pixels onto the selection or image.  You may select the percentage of pixels to modify and the number of times to repeat the process.";
  225.   const gchar *pick_help =
  226.     "This plug-in replaces a pixel with a random adjacent pixel.  You may select the percentage of pixels to modify and the number of times to repeat the process.";
  227.   const gchar *slur_help =
  228.     "This plug-in slurs (melts like a bunch of icicles) an image.  You may select the percentage of pixels to modify and the number of times to repeat the process.";
  229.  
  230.   const gchar *author = "Miles O'Neal  <meo@rru.com>  http://www.rru.com/~meo/";
  231.   const gchar *copyrights = "Miles O'Neal, Spencer Kimball, Peter Mattis, Torsten Martinsen, Brian Degenhardt, Federico Mena Quintero, Stephen Norris, Daniel Cotting";
  232.   const gchar *copyright_date = "1995-1998";
  233.  
  234.   gimp_install_procedure (PLUG_IN_NAME[0],
  235.               (gchar *) hurl_blurb,
  236.               (gchar *) hurl_help,
  237.               (gchar *) author,
  238.               (gchar *) copyrights,
  239.               (gchar *) copyright_date,
  240.               N_("<Image>/Filters/Noise/Hurl..."),
  241.               "RGB*, GRAY*, INDEXED*",
  242.               GIMP_PLUGIN,
  243.               nargs, 0,
  244.               args, NULL);
  245.  
  246.   gimp_install_procedure (PLUG_IN_NAME[1],
  247.               (gchar *) pick_blurb,
  248.               (gchar *) pick_help,
  249.               (gchar *) author,
  250.               (gchar *) copyrights,
  251.               (gchar *) copyright_date,
  252.               N_("<Image>/Filters/Noise/Pick..."),
  253.               "RGB*, GRAY*, INDEXED*",
  254.               GIMP_PLUGIN,
  255.               nargs, 0,
  256.               args, NULL);
  257.  
  258.   gimp_install_procedure (PLUG_IN_NAME[2],
  259.               (gchar *) slur_blurb,
  260.               (gchar *) slur_help,
  261.               (gchar *) author,
  262.               (gchar *) copyrights,
  263.               (gchar *) copyright_date,
  264.               N_("<Image>/Filters/Noise/Slur..."),
  265.               "RGB*, GRAY*, INDEXED*",
  266.               GIMP_PLUGIN,
  267.               nargs, 0,
  268.               args, NULL);
  269. }
  270.  
  271. /*********************************
  272.  *
  273.  *  run() - main routine
  274.  *
  275.  *  This handles the main interaction with the GIMP itself,
  276.  *  and invokes the routine that actually does the work.
  277.  *
  278.  ********************************/
  279.  
  280. static void
  281. run (gchar   *name,
  282.      gint     nparams,
  283.      GimpParam  *param,
  284.      gint    *nreturn_vals,
  285.      GimpParam **return_vals)
  286. {
  287.   GimpDrawable *drawable;
  288.   GimpRunModeType run_mode;
  289.   GimpPDBStatusType status = GIMP_PDB_SUCCESS;        /* assume the best! */
  290.   gchar *rndm_type_str = '\0';
  291.   gchar prog_label[32];
  292.   static GimpParam values[1];
  293.   /*
  294.    *  Get the specified drawable, do standard initialization.
  295.    */
  296.   if (strcmp(name, PLUG_IN_NAME[0]) == 0)
  297.     rndm_type = RNDM_HURL;
  298.   else if (strcmp(name, PLUG_IN_NAME[1]) == 0)
  299.     rndm_type = RNDM_PICK;
  300.   else if (strcmp(name, PLUG_IN_NAME[2]) == 0)
  301.     rndm_type = RNDM_SLUR;
  302.  
  303.   run_mode = param[0].data.d_int32;
  304.   drawable = gimp_drawable_get(param[2].data.d_drawable);
  305.  
  306.   values[0].type = GIMP_PDB_STATUS;
  307.   values[0].data.d_status = status;
  308.   *nreturn_vals = 1;
  309.   *return_vals = values;
  310.   /*
  311.    *  Make sure the drawable type is appropriate.
  312.    */
  313.   if (gimp_drawable_is_rgb(drawable->id) ||
  314.       gimp_drawable_is_gray(drawable->id) ||
  315.       gimp_drawable_is_indexed(drawable->id))
  316.     {
  317.       switch (run_mode)
  318.     {
  319.       /*
  320.        *  If we're running interactively, pop up the dialog box.
  321.        */
  322.     case GIMP_RUN_INTERACTIVE:
  323.       INIT_I18N_UI();
  324.       gimp_get_data(PLUG_IN_NAME[rndm_type - 1], &pivals);
  325.       if (!randomize_dialog())        /* return on Cancel */
  326.         return;
  327.       break;
  328.       /*
  329.        *  If we're not interactive (probably scripting), we
  330.        *  get the parameters from the param[] array, since
  331.        *  we don't use the dialog box.  Make sure they all
  332.        *  parameters have legitimate values.
  333.        */
  334.     case GIMP_RUN_NONINTERACTIVE:
  335.       if (nparams != 7)
  336.         {
  337.           status = GIMP_PDB_CALLING_ERROR;
  338.         }
  339.       else
  340.         {
  341.           pivals.rndm_pct = (gdouble) param[3].data.d_float;
  342.           pivals.rndm_rcount = (gdouble) param[4].data.d_float;
  343.           pivals.seed_type = (gint) param[5].data.d_int32;
  344.           pivals.rndm_seed = (gint) param[6].data.d_int32;
  345.  
  346.           if ((rndm_type != RNDM_PICK &&
  347.            rndm_type != RNDM_SLUR &&
  348.            rndm_type != RNDM_HURL) ||
  349.           (pivals.rndm_pct < 1.0 || pivals.rndm_pct > 100.0) ||
  350.           (pivals.rndm_rcount < 1.0 || pivals.rndm_rcount > 100.0))
  351.         {
  352.           status = GIMP_PDB_CALLING_ERROR;
  353.         }
  354.         }
  355.       break;
  356.       /*
  357.        *  If we're running with the last set of values, get those values.
  358.        */
  359.     case GIMP_RUN_WITH_LAST_VALS:
  360.       gimp_get_data (PLUG_IN_NAME[rndm_type - 1], &pivals);
  361.       break;
  362.       /*
  363.        *  Hopefully we never get here!
  364.        */
  365.     default:
  366.       break;
  367.         }
  368.       if (status == GIMP_PDB_SUCCESS)
  369.     {
  370.       /*
  371.        *  JUST DO IT!
  372.        */
  373.       switch (rndm_type)
  374.         {
  375.         case RNDM_HURL: rndm_type_str = "hurl"; break;
  376.         case RNDM_PICK: rndm_type_str = "pick"; break;
  377.         case RNDM_SLUR: rndm_type_str = "slur"; break;
  378.             }
  379.       sprintf (prog_label, "%s (%s)", gettext(RNDM_VERSION[rndm_type - 1]),
  380.            gettext(rndm_type_str));
  381.       gimp_progress_init(prog_label);
  382.       gimp_tile_cache_ntiles(2 * (drawable->width / gimp_tile_width() + 1));
  383.       /*
  384.        *  Initialize the rand() function seed
  385.        */
  386.       if (pivals.seed_type == SEED_TIME)
  387.         pivals.rndm_seed = time(NULL);
  388.  
  389.       srand (pivals.rndm_seed);
  390.  
  391.       randomize (drawable);
  392.       /*
  393.        *  If we ran interactively (even repeating) update the display.
  394.        */
  395.       if (run_mode != GIMP_RUN_NONINTERACTIVE)
  396.         {
  397.           gimp_displays_flush();
  398.             }
  399.       /*
  400.        *  If we use the dialog popup, set the data for future use.
  401.        */
  402.       if (run_mode == GIMP_RUN_INTERACTIVE)
  403.         {
  404.           gimp_set_data(PLUG_IN_NAME[rndm_type - 1], &pivals,
  405.                 sizeof(RandomizeVals));
  406.             }
  407.         }
  408.     }
  409.   else
  410.     {
  411.       /*
  412.        *  If we got the wrong drawable type, we need to complain.
  413.        */
  414.       status = GIMP_PDB_EXECUTION_ERROR;
  415.     }
  416.   /*
  417.    *  DONE!
  418.    *  Set the status where the GIMP can see it, and let go
  419.    *  of the drawable.
  420.    */
  421.   values[0].data.d_status = status;
  422.   gimp_drawable_detach(drawable);
  423. }
  424.  
  425. /*********************************
  426.  *
  427.  *  randomize_prepare_row()
  428.  *
  429.  *  Get a row of pixels.  If the requested row
  430.  *  is off the edge, clone the edge row.
  431.  *
  432.  ********************************/
  433.  
  434. static inline void
  435. randomize_prepare_row (GimpPixelRgn *pixel_rgn,
  436.                guchar    *data,
  437.                int        x,
  438.                int        y,
  439.                int        w)
  440. {
  441.   gint b;
  442.  
  443.   if (y == 0)
  444.     {
  445.       gimp_pixel_rgn_get_row(pixel_rgn, data, x, (y + 1), w);
  446.     }
  447.   else if (y == pixel_rgn->h)
  448.     {
  449.       gimp_pixel_rgn_get_row(pixel_rgn, data, x, (y - 1), w);
  450.     }
  451.   else
  452.     {
  453.       gimp_pixel_rgn_get_row(pixel_rgn, data, x, y, w);
  454.     }
  455.   /*
  456.    *  Fill in edge pixels
  457.    */
  458.   for (b = 0; b < pixel_rgn->bpp; b++)
  459.     {
  460.       data[-(gint)pixel_rgn->bpp + b] = data[b];
  461.       data[w * pixel_rgn->bpp + b] = data[(w - 1) * pixel_rgn->bpp + b];
  462.     }
  463. }
  464.  
  465. /*********************************
  466.  *
  467.  *  randomize()
  468.  *
  469.  *  Actually mess with the image.
  470.  *
  471.  ********************************/
  472.  
  473. static void
  474. randomize (GimpDrawable *drawable)
  475. {
  476.   GimpPixelRgn srcPR, destPR, destPR2, *sp, *dp, *tp;
  477.   gint width, height;
  478.   gint bytes;
  479.   guchar *dest, *d;
  480.   guchar *prev_row, *pr;
  481.   guchar *cur_row, *cr;
  482.   guchar *next_row, *nr;
  483.   guchar *tmp;
  484.   gint row, col;
  485.   gint x1, y1, x2, y2;
  486.   gint cnt;
  487.   gint has_alpha, ind;
  488.  
  489.   /*
  490.    *  Get the input area. This is the bounding box of the selection in
  491.    *  the image (or the entire image if there is no selection). Only
  492.    *  operating on the input area is simply an optimization. It doesn't
  493.    *  need to be done for correct operation. (It simply makes it go
  494.    *  faster, since fewer pixels need to be operated on).
  495.    */
  496.   gimp_drawable_mask_bounds(drawable->id, &x1, &y1, &x2, &y2);
  497.   /*
  498.    *  Get the size of the input image. (This will/must be the same
  499.    *  as the size of the output image.  Also get alpha info.
  500.    */
  501.   width = drawable->width;
  502.   height = drawable->height;
  503.   bytes = drawable->bpp;
  504.   has_alpha = gimp_drawable_has_alpha(drawable->id);
  505.   /*
  506.    *  allocate row buffers
  507.    */
  508.   prev_row = g_new (guchar, (x2 - x1 + 2) * bytes);
  509.   cur_row = g_new (guchar, (x2 - x1 + 2) * bytes);
  510.   next_row = g_new (guchar, (x2 - x1 + 2) * bytes);
  511.   dest = g_new (guchar, (x2 - x1) * bytes);
  512.  
  513.   /*
  514.    *  initialize the pixel regions
  515.    */
  516.   gimp_pixel_rgn_init(&srcPR, drawable, 0, 0, width, height, FALSE, FALSE);
  517.   gimp_pixel_rgn_init(&destPR, drawable, 0, 0, width, height, TRUE, TRUE);
  518.   gimp_pixel_rgn_init(&destPR2, drawable, 0, 0, width, height, TRUE, TRUE);
  519.   sp = &srcPR;
  520.   dp = &destPR;
  521.   tp = NULL;
  522.  
  523.   pr = prev_row + bytes;
  524.   cr = cur_row + bytes;
  525.   nr = next_row + bytes;
  526.  
  527.   for (cnt = 1; cnt <= pivals.rndm_rcount; cnt++)
  528.     {
  529.       /*
  530.        *  prepare the first row and previous row
  531.        */
  532.       randomize_prepare_row(sp, pr, x1, y1 - 1, (x2 - x1));
  533.       randomize_prepare_row(dp, cr, x1, y1, (x2 - x1));
  534.       /*
  535.        *  loop through the rows, applying the selected convolution
  536.        */
  537.       for (row = y1; row < y2; row++)
  538.     {
  539.       /*  prepare the next row  */
  540.       randomize_prepare_row(sp, nr, x1, row + 1, (x2 - x1));
  541.  
  542.       d = dest;
  543.       ind = 0;
  544.       for (col = 0; col < (x2 - x1) * bytes; col++)
  545.         {
  546.           if (((rand() % 100)) <= (gint) pivals.rndm_pct)
  547.         {
  548.           switch (rndm_type)
  549.             {
  550.               /*
  551.                *  HURL
  552.                *      Just assign a random value.
  553.                */
  554.             case RNDM_HURL:
  555.               *d++ = rand() % 256;
  556.                       break;
  557.               /*
  558.                *  PICK
  559.                *      pick at random from a neighboring pixel.
  560.                */
  561.             case RNDM_PICK:
  562.               switch (rand() % 9)
  563.             {
  564.             case 0:
  565.               *d++ = (gint) pr[col - bytes];
  566.               break;
  567.             case 1:
  568.               *d++ = (gint) pr[col];
  569.               break;
  570.             case 2:
  571.               *d++ = (gint) pr[col + bytes];
  572.               break;
  573.             case 3:
  574.               *d++ = (gint) cr[col - bytes];
  575.               break;
  576.             case 4:
  577.               *d++ = (gint) cr[col];
  578.               break;
  579.             case 5:
  580.               *d++ = (gint) cr[col + bytes];
  581.               break;
  582.             case 6:
  583.               *d++ = (gint) nr[col - bytes];
  584.               break;
  585.             case 7:
  586.               *d++ = (gint) nr[col];
  587.               break;
  588.             case 8:
  589.               *d++ = (gint) nr[col + bytes];
  590.               break;
  591.                         }
  592.                       break;
  593.               /*
  594.                *  SLUR
  595.                *      80% chance it's from directly above,
  596.                *      10% from above left,
  597.                *      10% from above right.
  598.                */
  599.             case RNDM_SLUR:
  600.               switch (rand() % 10)
  601.             {
  602.             case 0:
  603.               *d++ = (gint) pr[col - bytes];
  604.               break;
  605.             case 9:
  606.               *d++ = (gint) pr[col + bytes];
  607.               break;
  608.             default:
  609.               *d++ = (gint) pr[col];
  610.               break;
  611.                         }
  612.                       break;
  613.                     }
  614.           /*
  615.            *  Otherwise, this pixel was not selected for randomization,
  616.            *  so use the current value.
  617.            */
  618.                 }
  619.           else
  620.         {
  621.           *d++ = (gint) cr[col];
  622.                 }
  623.             }
  624.       /*
  625.        *  Save the modified row, shuffle the row pointers, and every
  626.        *  so often, update the progress meter.
  627.        */
  628.       gimp_pixel_rgn_set_row(dp, dest, x1, row, (x2 - x1));
  629.  
  630.       tmp = pr;
  631.       pr = cr;
  632.       cr = nr;
  633.       nr = tmp;
  634.  
  635.       if (PROG_UPDATE_TIME)
  636.         gimp_progress_update((double) row / (double) (y2 - y1));
  637.         }
  638.       /*
  639.        *  if we have more cycles to perform, swap the src and dest Pixel Regions
  640.        */
  641.       if (cnt < pivals.rndm_rcount)
  642.     {
  643.       if (tp != NULL)
  644.         {
  645.           tp = dp;
  646.           dp = sp;
  647.           sp = tp;
  648.             }
  649.       else
  650.         {
  651.           tp = &srcPR;
  652.           sp = &destPR;
  653.           dp = &destPR2;
  654.             }
  655.         }
  656.     }
  657.   gimp_progress_update((double) 100);
  658.   /*
  659.    *  update the randomized region
  660.    */
  661.   gimp_drawable_flush(drawable);
  662.   gimp_drawable_merge_shadow(drawable->id, TRUE);
  663.   gimp_drawable_update(drawable->id, x1, y1, (x2 - x1), (y2 - y1));
  664.   /*
  665.    *  clean up after ourselves.
  666.    */
  667.   g_free (prev_row);
  668.   g_free (cur_row);
  669.   g_free (next_row);
  670.   g_free (dest);
  671. }
  672.  
  673. /*********************************
  674.  *
  675.  *  GUI ROUTINES
  676.  *
  677.  ********************************/
  678.  
  679.  
  680. /*********************************
  681.  *
  682.  *  randomize_dialog() - set up the plug-in's dialog box
  683.  *
  684.  ********************************/
  685.  
  686. static gint
  687. randomize_dialog (void)
  688. {
  689.   GtkWidget *dlg;
  690.   GtkWidget *frame;
  691.   GtkWidget *table;
  692.   GtkWidget *seed_hbox;
  693.   GtkObject *adj;
  694.  
  695.   gimp_ui_init ("randomize", FALSE);
  696.  
  697.   dlg = gimp_dialog_new (gettext (RNDM_VERSION[rndm_type - 1]), "randomize",
  698.              gimp_standard_help_func, "filters/randomize.html",
  699.              GTK_WIN_POS_MOUSE,
  700.              FALSE, TRUE, FALSE,
  701.  
  702.              _("OK"), randomize_ok_callback,
  703.              NULL, NULL, NULL, TRUE, FALSE,
  704.              _("Cancel"), gtk_widget_destroy,
  705.              NULL, 1, NULL, FALSE, TRUE,
  706.  
  707.              NULL);
  708.  
  709.   gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
  710.               GTK_SIGNAL_FUNC (gtk_main_quit),
  711.               NULL);
  712.  
  713.   gimp_help_init ();
  714.  
  715.   /*
  716.    *  Parameter settings
  717.    *
  718.    *  First set up the basic containers, label them, etc.
  719.    */
  720.   frame = gtk_frame_new (_("Parameter Settings"));
  721.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
  722.   gtk_container_set_border_width (GTK_CONTAINER (frame), 6);
  723.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), frame, TRUE, TRUE, 0);
  724.  
  725.   table = gtk_table_new (3, 3, FALSE);
  726.   gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  727.   gtk_table_set_row_spacings (GTK_TABLE (table), 2);
  728.   gtk_container_set_border_width (GTK_CONTAINER (table), 4);
  729.   gtk_container_add (GTK_CONTAINER (frame), table);
  730.   gtk_widget_show(table);
  731.  
  732.   /*  Random Seed  */
  733.   seed_hbox = gimp_random_seed_new (&pivals.rndm_seed,
  734.                     &pivals.seed_type,
  735.                     SEED_TIME, SEED_USER);
  736.   gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
  737.                              _("Random Seed:"), 1.0, 0.5,
  738.                              seed_hbox, 1, TRUE);
  739.  
  740.   /*
  741.    *  Randomization percentage label & scale (1 to 100)
  742.    */
  743.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 1,
  744.                   _("Randomization (%):"), SCALE_WIDTH, 0,
  745.                   pivals.rndm_pct, 1.0, 100.0, 1.0, 10.0, 0,
  746.                   TRUE, 0, 0,
  747.                   _("Percentage of pixels to be filtered"), NULL);
  748.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  749.                       GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
  750.                       &pivals.rndm_pct);
  751.  
  752.   /*
  753.    *  Repeat count label & scale (1 to 100)
  754.    */
  755.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 2,
  756.                   _("Repeat:"), SCALE_WIDTH, 0,
  757.                   pivals.rndm_rcount, 1.0, 100.0, 1.0, 10.0, 0,
  758.                   TRUE, 0, 0,
  759.                   _("Number of times to apply filter"), NULL);
  760.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  761.                       GTK_SIGNAL_FUNC (gimp_double_adjustment_update),
  762.                       &pivals.rndm_rcount);
  763.  
  764.   gtk_widget_show (frame);
  765.  
  766.   gtk_widget_show (dlg);
  767.  
  768.   gtk_main ();
  769.   gimp_help_free ();
  770.   gdk_flush ();
  771.  
  772.   return rndm_int.run;
  773. }
  774.  
  775. static void
  776. randomize_ok_callback (GtkWidget *widget,
  777.                gpointer   data)
  778. {
  779.   rndm_int.run = TRUE;
  780.  
  781.   gtk_widget_destroy (GTK_WIDGET (data));
  782. }
  783.